package com.wut.clock.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.wut.clock.common.constant.CommentConstant;
import com.wut.clock.common.exception.Asserts;
import com.wut.clock.common.util.PageUtil;
import com.wut.clock.common.util.ServletUtil;
import com.wut.clock.dto.portal.ArticlePortalParams;
import com.wut.clock.entity.Article;
import com.wut.clock.entity.ArticleTag;
import com.wut.clock.entity.Comment;
import com.wut.clock.entity.Tag;
import com.wut.clock.event.EventProducer;
import com.wut.clock.mapper.*;
import com.wut.clock.service.IArticleService;
import com.wut.clock.util.ShiroUtil;
import com.wut.clock.vo.portal.ArticleCommentVo;
import com.wut.clock.vo.portal.ArticlePortalVo;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author ZYH
 * @unit D9Lab
 * @description 文章接口实现类
 * @date 2022/6/7 21:01
 */
@Service
@RequiredArgsConstructor
@SuppressWarnings("unchecked")
public class ArticleServiceImpl implements IArticleService {

    private final ArticleMapper articleMapper;

    private final ArticleTagMapper articleTagMapper;

    private final SysUserMapper userMapper;

    private final CategoryMapper categoryMapper;

    private final TagMapper tagMapper;

    private final CommentMapper commentMapper;

    private final EventProducer eventProducer;


    @Transactional
    @Override
    public int addArticle(ArticlePortalParams articlePortalParams) {
        Article article = new Article();
        articlePortalParams.setUserId(ShiroUtil.getUserId());
        BeanUtils.copyProperties(articlePortalParams,article);
        articleMapper.insert(article);
        Integer articleId = article.getId();
        String[] tagIdList = articlePortalParams.getTagIdString().split(",");
        addArticleTag(tagIdList,articleId);
        return 1;
    }

    @Transactional
    @Override
    public int updateArticle(ArticlePortalParams articlePortalParams) {
        Integer articleId = articlePortalParams.getId();
        Article article = articleMapper.selectById(articleId);
        if(article == null) Asserts.fail("文章不存在");
        BeanUtils.copyProperties(articlePortalParams,article);
        articleMapper.updateById(article);

        // 添加之前先删除标签关联
        articleTagMapper.delete(new QueryWrapper<ArticleTag>().eq("article_id", articleId));

        // 添加新标签
        String[] tagIdList = articlePortalParams.getTagIdString().split(",");
        addArticleTag(tagIdList,articleId);
        return 1;
    }

    private void addArticleTag(String[] tagIdList,Integer articleId){
        for (String tagIdString : tagIdList) {
            int tagId = Integer.parseInt(tagIdString);
            ArticleTag articleTag = new ArticleTag();
            articleTag.setTagId(tagId);
            articleTag.setArticleId(articleId);
            articleTagMapper.insert(articleTag);
        }
    }

    @Transactional
    @Override
    public int deleteArticle(Integer articleId) {
        // 删除关联的标签
        articleTagMapper.delete(new QueryWrapper<ArticleTag>().eq("article_id", articleId));
        // 删除文章的评论
        commentMapper.delete(new QueryWrapper<Comment>().eq("article_id",articleId));
        return articleMapper.deleteById(articleId);
    }

    @Override
    public List<ArticlePortalVo> getOwnArticleList(Integer pageNum,Integer pageSize, Integer categoryId,String yearMonth, String keywords) {
        PageHelper.startPage(pageNum,pageSize);
        return articleMapper.getOwnArticleList(ShiroUtil.getUserId(),categoryId,yearMonth,keywords);
    }

    @Override
    public ArticlePortalVo getArticleDetail(Integer articleId) {
        Article article = articleMapper.selectById(articleId);
        @NotBlank String categoryName = categoryMapper.selectById(article.getCategoryId()).getCategoryName();
        String nickname = userMapper.selectById(article.getUserId()).getNickname();
        List<ArticleTag> articleTagList = articleTagMapper.selectList(new QueryWrapper<ArticleTag>().eq("article_id", articleId));
        List<Tag> tagList = new ArrayList<>();
        articleTagList.forEach(at-> tagList.add(tagMapper.selectById(at.getTagId())));
        ArticlePortalVo articlePortalVo = new ArticlePortalVo();
        BeanUtils.copyProperties(article,articlePortalVo);
        articlePortalVo.setNickname(nickname);
        articlePortalVo.setCategoryName(categoryName);
        articlePortalVo.setTagList(tagList);

        //更新文章浏览量
        eventProducer.fireArticleViewEvent(ServletUtil.getRequest(),articleId);
        return articlePortalVo;
    }

    @Override
    public List<ArticleCommentVo> getArticleComment(Integer pageNum,Integer pageSize,Integer articleId) {
        List<ArticleCommentVo> articleCommentVoList  = articleMapper.getArticleComment(articleId);
        List<ArticleCommentVo> commentVoList = buildCommentTree(articleCommentVoList);
        return PageUtil.startPage(commentVoList,pageNum,pageSize);
    }

    private List<ArticleCommentVo> buildCommentTree(List<ArticleCommentVo> articleCommentVoList) {
        List<ArticleCommentVo> res = articleCommentVoList.stream()
                .filter(commentVo -> commentVo.getTopicType().equals(CommentConstant.TopicType.ARTICLE.getCode()))
                .sorted(Comparator.comparing(Comment::getScore))
                .map(commentVo -> convert(commentVo, articleCommentVoList))
                .collect(Collectors.toList());
        return res;
    }

    private ArticleCommentVo convert(ArticleCommentVo commentVo,List<ArticleCommentVo> commentVos) {
        List<ArticleCommentVo> children = commentVos.stream()
                .filter(subComment -> subComment.getTopicType().equals(CommentConstant.TopicType.COMMENT.getCode())
                        && subComment.getTopicId().equals(commentVo.getId()))
                .map(subComment -> convert(subComment, commentVos))
                .collect(Collectors.toList());
        commentVo.setChildren(children);
        return commentVo;
    }
}
